package com.qqtech.oss.aliyun;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Random;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import com.qqtech.core.common.util.StringUtil;

@SuppressWarnings("unused")
public class OSSObject {
	private static final Logger log = LoggerFactory.getLogger(OSSObject.class);
	private OSSClient client;
	private FileClientConfig fileClientConfig;
	private String defaultBucketName;

	public OSSObject(FileClientConfig fileClientConfig) {
		this.fileClientConfig = fileClientConfig;
		this.defaultBucketName = fileClientConfig.getDefaultBucketName();

		String ossEndpoint = fileClientConfig.getEndpoint();
		String ossAccessKeyId = fileClientConfig.getAccessKeyId();
		String ossSecretAccessKey = fileClientConfig.getSecretAccessKey();

		ClientConfiguration clientConfiguration = createDefaultConfiguration();
		this.client = new OSSClient(ossEndpoint, ossAccessKeyId, ossSecretAccessKey);
	}

	// 设置网络参数
	private ClientConfiguration createDefaultConfiguration() {
		ClientConfiguration conf = new ClientConfiguration();
		conf.setMaxConnections(50);
		conf.setConnectionTimeout(8000); // 8秒
		conf.setMaxErrorRetry(2);
		conf.setSocketTimeout(300000); // 5分钟
		return conf;
	}

	public UploadResult putObject(String bucketName, String key, String filePath) throws FileClientException {
		File file = new File(filePath);
		return putObject(bucketName, key, file);
	}

	public UploadResult putObject(String bucketName, String key, File file) throws FileClientException {
		InputStream inputStream;
		try {
			inputStream = new FileInputStream(file);
		} catch (FileNotFoundException e) {
			throw new FileClientException(e);
		}
		return putObject(bucketName, key, inputStream, file.length());
	}

	public UploadResult putObject(String key, String filePath) throws FileClientException {
		return putObject(defaultBucketName, key, filePath);
	}

	public UploadResult putObject(String key, File file) throws FileClientException {
		return putObject(defaultBucketName, key, file);
	}

	public UploadResult putObject(String bucketName, String key, InputStream in) throws FileClientException {
		return putObject(bucketName, key, in, -1);
	}

	public UploadResult putObject(String key, InputStream in) throws FileClientException {
		return putObject(defaultBucketName, key, in, -1);
	}

	public UploadResult putObject(String key, InputStream in, long fileSize) throws FileClientException {
		return putObject(defaultBucketName, key, in, fileSize);
	}

	public UploadResult putObject(String bucketName, String key, InputStream in, long fileSize)
			throws FileClientException {
		try {
			// 创建上传Object的Metadata
			ObjectMetadata meta = new ObjectMetadata();

			// 必须设置ContentLength
			if (fileSize <= 0) {
				fileSize = in.available();
			}
			meta.setContentLength(fileSize);

			// 需要正确设置content type，否则，缺省的content type都为application/octet-stream。
			// 如果类型是application/octst-stream，则在访问文件时，
			// 会导致下载操作。在浏览器中，会弹出下载保存的对话框
			setContentType(key, meta);

			// 上传Object.
			String formatKey = formatKey(key);
			// 目标文件已经存在，则存储的文件名随机生成
			if (client.doesObjectExist(bucketName, formatKey)) {
				formatKey = buidRamdonFilename(formatKey);
			}

			PutObjectResult result = client.putObject(bucketName, formatKey, in);
			String etag = result.getETag();
			if (etag != null) {
				UploadResult uploadResult = new UploadResult(true, wrapOssFormatKey(formatKey), etag);
				uploadResult.setFileSize(fileSize);
				return uploadResult;
			}
			return new UploadResult();
		} catch (Exception e) {
			throw new FileClientException(e);
		}
	}

	/**
	 * a.c -> ${Ramdon}.c /a.c -> /${Ramdon}.c /d/a.c -> /d/${Ramdon}.c
	 * 
	 * @param filePath
	 * @return
	 */
	private String buidRamdonFilename(String filePath) {
		String ext = StringUtil.getExtensionName(filePath);
		String filename = System.currentTimeMillis() + "" + new Random().nextInt(10000) + "." + ext;
		File file = new File(filePath);
		String parent = file.getParent();
		if (parent == null) {
			return filename;
		}
		if (parent.equals("/")) {
			return parent + filename;
		} else {
			return parent + "/" + filename;
		}
	}

	private void setContentType(String key, ObjectMetadata meta) {
		String contentType = ContentTypeUtil.getContentType(key);
		if (contentType != null && contentType.length() > 0) {
			meta.setContentType(contentType);
		}
	}

	// /aa/cc.jpg => aa/cc.jpg
	// \aa\cc.jpg => aa/cc.jpg
	// \\aa/cc.jpg => aa/cc.jpg
	private String formatKey(String key) {
		if (key == null || key.length() == 0) {
			throw new NullPointerException("key can't be empty");
		}
		key = key.trim().replaceAll("\\\\", "/");
		if (key.startsWith("/")) {
			return key.substring(1);
		} else {
			return key;
		}
	}

	private String wrapOssFormatKey(String key) {
		return "/" + key;
	}
}
